/**
 * 权限自动计算工具
 * 参考 xz-crm-b 项目实现
 */
import type { RouteRecordRaw } from "vue-router";

/**
 * 角色类型常量
 * 参考 xz-crm-b 项目，定义清晰的角色类型编码
 */
export const RoleType = {
  /** 平台管理员 */
  PLATFORM_ADMIN: 1,
  /** 租户超级管理员 */
  SUPER_ADMIN: 11,
  /** 站点管理员 */
  SITE_ADMIN: 21,
  /** 租户普通操作员 */
  OPERATOR: 31,
} as const;

export type RoleType = (typeof RoleType)[keyof typeof RoleType];

/**
 * 角色类型配置
 */
export interface RoleTypeConfig {
  value: RoleType;
  label: string;
  code: string;
  /** 是否为固定权限角色（固定权限角色的权限不可编辑） */
  fixedPermission: boolean;
}

/**
 * 所有角色类型配置
 */
export const roleTypeList: RoleTypeConfig[] = [
  {
    value: RoleType.PLATFORM_ADMIN,
    label: "平台管理员",
    code: "PLATFORM_ADMIN",
    fixedPermission: true,
  },
  {
    value: RoleType.SUPER_ADMIN,
    label: "租户超级管理员",
    code: "SUPER_ADMIN",
    fixedPermission: true,
  },
  {
    value: RoleType.SITE_ADMIN,
    label: "站点管理员",
    code: "SITE_ADMIN",
    fixedPermission: false, // 站点管理员权限可编辑
  },
  {
    value: RoleType.OPERATOR,
    label: "普通操作员",
    code: "OPERATOR",
    fixedPermission: false,
  },
];

/**
 * 根据角色编码获取角色类型
 */
export function getRoleTypeByCode(roleCode: string): RoleType | undefined {
  return roleTypeList.find((r) => r.code === roleCode)?.value;
}

/**
 * 获取当前角色的权限列表
 * @param route 路由配置
 * @param roleType 角色类型
 * @param fixedPermission 是否只获取固定权限
 */
export function getRoleRouteCode(
  route: RouteRecordRaw[],
  roleType: RoleType,
  fixedPermission: boolean = false
): string[] {
  const codes: string[] = [];

  function traverse(routes: RouteRecordRaw[]) {
    routes.forEach((r) => {
      const meta = r.meta as any;

      // 跳过隐藏的菜单
      if (meta?.hideInMenu) {
        return;
      }

      // 检查当前角色是否有该页面权限
      let hasAuth = false;
      if (meta?.$pageAuthorityRoleTypes) {
        hasAuth = meta.$pageAuthorityRoleTypes.includes(roleType);
      } else if (meta?.permission) {
        // 路由没有配置页面权限时，默认有权限
        hasAuth = true;
      }

      if (hasAuth) {
        // 添加页面权限
        if (meta?.permission) {
          const permCode =
            typeof meta.permission === "string"
              ? meta.permission
              : meta.permission.code;
          if (permCode) {
            if (fixedPermission) {
              codes.push(permCode);
            } else if (meta?.hideInUseAuthority) {
              // 在权限设置时隐藏的权限也要添加
              codes.push(permCode);
            }
          }
        }

        // 递归处理子路由
        if (r.children && !meta?.hide) {
          traverse(r.children);
        }

        // 处理按钮权限
        if (meta?.$actions && fixedPermission) {
          Object.keys(meta.$actions).forEach((key) => {
            const action = meta.$actions[key];
            let actionHasAuth = true;

            if (action.$actionsAuthorityRoleTypes) {
              actionHasAuth =
                action.$actionsAuthorityRoleTypes.includes(roleType);
            }

            if (actionHasAuth && action.code) {
              codes.push(action.code);
            }
          });
        }
      }
    });
  }

  traverse(route);
  return codes;
}

/**
 * 路由数据扁平化，子级包含所有父级数据
 */
function formatRoutes(routes: RouteRecordRaw[]): any[] {
  function flatten(routes: RouteRecordRaw[], parentCode: string[] = []): any[] {
    return routes.map((r) => {
      const meta = r.meta as any;
      const permCode =
        typeof meta?.permission === "string"
          ? meta.permission
          : meta?.permission?.code;

      return {
        ...r,
        parentCode,
        children: flatten(
          r.children || [],
          permCode ? [...parentCode, permCode] : parentCode
        ),
      };
    });
  }
  return flatten(routes);
}

/**
 * 获取权限码的所有父级权限码
 */
function getCodeParent(routeList: any[], code: string): string[] {
  let parentCode: string[] = [];

  function search(routes: any[]) {
    for (const route of routes) {
      const meta = route.meta as any;
      const permCode =
        typeof meta?.permission === "string"
          ? meta.permission
          : meta?.permission?.code;

      if (permCode === code) {
        parentCode = route.parentCode;
        // 如果路径等于第一个子路径，需要包含子路径的权限码
        if (route.path === route.children?.[0]?.path) {
          const childPermCode =
            typeof route.children[0].meta?.permission === "string"
              ? route.children[0].meta.permission
              : route.children[0].meta?.permission?.code;
          if (childPermCode) {
            parentCode = [...route.parentCode, childPermCode];
          }
        }
        return;
      }

      // 检查按钮权限
      if (meta?.$actions) {
        Object.keys(meta.$actions).forEach((key) => {
          const action = meta.$actions[key];
          if (action.code === code && key === "_pageViewPermission") {
            // 有页面权限才可见
            parentCode = permCode
              ? [...route.parentCode, permCode]
              : route.parentCode;
          }
        });
      }

      if (route.children) {
        search(route.children);
      }
    }
  }

  search(routeList);
  return parentCode;
}

/**
 * 格式化权限码列表，自动添加父级权限
 */
function formatAuthorityCodes(
  routes: RouteRecordRaw[],
  authorityCodes: string[]
): string[] {
  const routeList = formatRoutes(routes);
  const allParentCode: string[] = [];

  authorityCodes.forEach((code) => {
    const parentCode = getCodeParent(routeList, code);
    allParentCode.push(...parentCode);
  });

  return [...new Set([...allParentCode, ...authorityCodes])];
}

/**
 * 获取固定展示模块的权限码
 * 某些模块对所有角色都可见（如个人信息等）
 */
function getFixedShowModuleCodes(
  routes: RouteRecordRaw[],
  roleTypes: RoleType[]
): string[] {
  const fixedRoutes = routes.filter((r) => (r.meta as any)?.isFixedShowModule);
  const allAuthorityCodes: string[] = [];

  roleTypes.forEach((roleType) => {
    allAuthorityCodes.push(...getRoleRouteCode(fixedRoutes, roleType, true));
  });

  return [...new Set(allAuthorityCodes)];
}

/**
 * 用户信息接口返回的数据结构
 */
export interface UserAuthInfo {
  /** 用户自定义的权限码列表 */
  authorityCodes?: string[];
  /** 用户的角色列表 */
  roles: Array<{
    roleId: number;
    roleCode: string;
    roleType: RoleType;
  }>;
  /** 已开通的模块资源编码 */
  moduleResourceCodes?: string[];
  /** 是否开通A类账号（非店铺）*/
  isOpenAccountA?: boolean;
  /** 是否开通B类账号（店铺）*/
  isOpenAccountB?: boolean;
}

/**
 * 格式化用户的权限码列表
 * 这是权限计算的核心函数
 *
 * @param routes 所有路由配置
 * @param userInfo 用户信息
 * @returns 最终的权限码列表
 */
export function formatAuthorityCodeList(
  routes: RouteRecordRaw[],
  userInfo: UserAuthInfo
): string[] {
  // 1. 获取用户自定义的权限码
  let authorityCodes = userInfo.authorityCodes?.length
    ? [...userInfo.authorityCodes]
    : [];

  const roles = userInfo.roles || [];
  const moduleResourceCodes = userInfo.moduleResourceCodes || [];

  // 2. 根据已开通的模块过滤路由
  let formatRoutes = routes;
  if (moduleResourceCodes.indexOf("ALL") === -1) {
    formatRoutes = routes
      .map((r) => {
        const meta = r.meta as any;
        if (!meta?.paidItemCode) {
          return r;
        }
        if (moduleResourceCodes.indexOf(meta.paidItemCode) === -1) {
          // 模块未开通，标记为隐藏
          return {
            ...r,
            meta: {
              ...meta,
              notActivatedModule: true,
              hide: true,
            },
          };
        }
        return r;
      })
      .filter((r) => !(r.meta as any)?.notActivatedModule);
  }

  // 3. 检查账号类型权限（如果有组织类型概念）
  // TODO: 根据实际业务调整
  // if (struInfo.orgType === 4 && !userInfo.isOpenAccountB) {
  //   return getFixedShowModuleCodes(formatRoutes, roles.map(r => r.roleType))
  // }

  // 4. 计算所有角色的权限
  const allAuthorityCodes: string[] = [];
  let hasCanEditRole = false;

  roles.forEach((role) => {
    const roleConfig = roleTypeList.find((r) => r.value === role.roleType);
    const fixedPermission = roleConfig?.fixedPermission || false;

    if (fixedPermission) {
      // 固定权限角色：权限不可编辑，直接从路由配置中提取
      allAuthorityCodes.push(
        ...getRoleRouteCode(formatRoutes, role.roleType, true)
      );
    } else {
      // 可编辑权限角色
      // 先添加在权限设置页隐藏的权限
      allAuthorityCodes.push(
        ...getRoleRouteCode(formatRoutes, role.roleType, false)
      );
      hasCanEditRole = true;
    }
  });

  // 5. 如果存在可编辑角色，合并用户自定义权限
  if (hasCanEditRole) {
    authorityCodes = formatAuthorityCodes(formatRoutes, authorityCodes);
    allAuthorityCodes.push(...authorityCodes);
  }

  // 6. 添加固定展示模块的权限
  const fixedShowModuleCodes = getFixedShowModuleCodes(
    formatRoutes,
    roles.map((r) => r.roleType)
  );

  // 7. 去重并返回
  return [...new Set([...allAuthorityCodes, ...fixedShowModuleCodes])];
}
